//Air001_ST7789_mini.ino 验证OK
#include <SPI.h>

// ==================== 屏幕引脚配置 ====================
#define TFT_CS   PA_4
#define TFT_DC   PB_0
#define TFT_RST  PB_1
#define TFT_BL   PB_2  // 背光控制引脚

// ==================== 全局变量 ====================
const uint16_t SCREEN_WIDTH = 240;
const uint16_t SCREEN_HEIGHT = 240;

int16_t cursor_x = 0;
int16_t cursor_y = 0;
uint16_t textcolor = 0xFFFF;    // 默认白色文本
uint16_t textbgcolor = 0x0000;  // 默认黑色背景
uint8_t textsize = 1;

// ==================== 微型字体定义 ====================
const char SUPPORTED_CHARS[] = " 0123456789.VAWmh"; // 添加空格字符

// 5×7像素字体数据
const uint8_t FONT_DATA_5x7[] PROGMEM = {
  // 空格 (32) - 全空
  0x00, 0x00, 0x00, 0x00, 0x00,
  // '0' (48)
  0x3E, 0x51, 0x49, 0x45, 0x3E,
  // '1' (49)
  0x00, 0x42, 0x7F, 0x40, 0x00,
  // '2' (50)
  0x42, 0x61, 0x51, 0x49, 0x46,
  // '3' (51)
  0x21, 0x41, 0x45, 0x4B, 0x31,
  // '4' (52)
  0x18, 0x14, 0x12, 0x7F, 0x10,
  // '5' (53)
  0x27, 0x45, 0x45, 0x45, 0x39,
  // '6' (54)
  0x3C, 0x4A, 0x49, 0x49, 0x30,
  // '7' (55)
  0x01, 0x71, 0x09, 0x05, 0x03,
  // '8' (56)
  0x36, 0x49, 0x49, 0x49, 0x36,
  // '9' (57)
  0x06, 0x49, 0x49, 0x29, 0x1E,
  // '.' (46) 小数点
  0x00, 0x00, 0x60, 0x60, 0x00,
  // 'V' (86) 大写V
  0x1F, 0x20, 0x40, 0x20, 0x1F,
  // 'A' (65) 大写A
  0x7C, 0x12, 0x11, 0x12, 0x7C,
  // 'W' (87) 大写W
  0x7F, 0x20, 0x18, 0x20, 0x7F,
  // 'm' (109) 小写m
  0x00, 0x7C, 0x08, 0x04, 0x78,
  // 'h' (104) 小写h
  0x7F, 0x08, 0x04, 0x04, 0x78
};

// 字体元数据
#define FONT_WIDTH 5
#define FONT_HEIGHT 7

// ==================== ST7789驱动函数 ====================
void tftStartWrite() {
  SPI.beginTransaction(SPISettings(12000000, MSBFIRST, SPI_MODE0));
  digitalWrite(TFT_CS, LOW);
}

void tftEndWrite() {
  digitalWrite(TFT_CS, HIGH);
  SPI.endTransaction();
}

void tftWriteCommand(uint8_t cmd) {
  digitalWrite(TFT_DC, LOW);
  tftStartWrite();
  SPI.transfer(cmd);
  tftEndWrite();
}

void tftWriteData(uint8_t data) {
  digitalWrite(TFT_DC, HIGH);
  tftStartWrite();
  SPI.transfer(data);
  tftEndWrite();
}

void tftWriteData16(uint16_t data) {
  digitalWrite(TFT_DC, HIGH);
  tftStartWrite();
  SPI.transfer16(data);
  tftEndWrite();
}

// 快速设置地址窗口
void tftSetAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
  tftWriteCommand(0x2A); // CASET
  tftWriteData16(x);
  tftWriteData16(x + w - 1);
  
  tftWriteCommand(0x2B); // RASET
  tftWriteData16(y);
  tftWriteData16(y + h - 1);
  
  tftWriteCommand(0x2C); // RAMWR
}

// 快速填充区域, 利用tftDrawFastHLine函数进行
void tftFillArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) {
  //按照行填充
  for (uint16_t i = 0; i < h; i++) {
    tftSetAddrWindow(x, y + i, w, 1);
    uint16_t buffer[240]; // 240像素缓冲区
    uint16_t totalPixels = (w > 240) ? 240 : w;
    // 填充缓冲区
    for (uint16_t j = 0; j < totalPixels; j++) {
      buffer[j] = color;
    }
    digitalWrite(TFT_DC, HIGH);
    tftStartWrite();
    SPI.transfer(buffer, totalPixels * 2); // 每个像素2字节
    tftEndWrite();
  }
}

void tftInit() {
  pinMode(TFT_DC, OUTPUT);
  pinMode(TFT_CS, OUTPUT);
  pinMode(TFT_RST, OUTPUT);

  digitalWrite(TFT_RST, HIGH);
  delay(50);
  digitalWrite(TFT_RST, LOW);
  delay(100); 
  digitalWrite(TFT_RST, HIGH);
  delay(150);
  
  SPI.begin();

  tftWriteCommand(0x01); // ST77XX_SWRESET 0x01 软件复位
  delay(150);
  tftWriteCommand(0x11); // ST77XX_SLPOUT 0x11 退出睡眠模式
  delay(10);

  tftWriteCommand(0x3A); // ST77XX_COLMOD 0x3A 设置颜色模式
  tftWriteData(0x55);    // 16-bit color (RGB565)
  delay(10);
  
  tftWriteCommand(0x36); // ST77XX_MADCTL 0x36 颜色格式和显示方向
  tftWriteData(0x08);    // 0x00默认RGB方向, 0x08 BGR顺序
  delay(10);

  tftWriteCommand(0x21); // ST77XX_INVON 0x21
  delay(10);
  
  tftWriteCommand(0x13);   // ST77XX_NORON 0x13 开启普通显示模式
  delay(10);

  tftWriteCommand(0x29); // ST77XX_DISPON 0x29 开启显示
  delay(10);
}

void setTextColor(uint16_t c, uint16_t bg) {
  textcolor = c;
  textbgcolor = bg;
}

void setCursor(int16_t x, int16_t y) {
  cursor_x = x;
  cursor_y = y;
}

// 优化后的字符绘制 - 批量传输像素
void drawChar(char c) {
  // 查找字符在字符集中的位置
  const char* ptr = strchr(SUPPORTED_CHARS, c);
  if (!ptr) return; // 不支持字符
  
  int16_t charIndex = ptr - SUPPORTED_CHARS;
  
  // 计算字体数据偏移量
  uint16_t dataOffset = charIndex * FONT_WIDTH;
  
  // 计算字符区域
  uint16_t charWidth = FONT_WIDTH * textsize;
  uint16_t charHeight = FONT_HEIGHT * textsize;
  
  for (uint8_t row = 0; row < FONT_HEIGHT; row++) {
    uint16_t lineBuffer[charWidth * textsize];  // 行缓冲区, 仅存储textsize行像素（一行水平+垂直放大后）
    // 准备当前行的水平+垂直放大的行数据
    for (uint8_t col = 0; col < FONT_WIDTH; col++) {
      uint8_t colData = pgm_read_byte(&FONT_DATA_5x7[dataOffset + col]);
      bool pixelOn = colData & (1 << row);
      uint16_t color = pixelOn ? textcolor : textbgcolor;
      
      for (uint8_t sx = 0; sx < textsize; sx++) {
        // 水平放大
        for (uint8_t sy = 0; sy < textsize; sy++) {
          // 垂直放大 - 每行重复textsize次
          lineBuffer[col * textsize + sx + sy * charWidth] = color;
        }
      }
    }
    // 传输当前行的放大数据 (textsize行)
    tftSetAddrWindow(cursor_x, cursor_y + row * textsize, charWidth, textsize);
    digitalWrite(TFT_DC, HIGH);
    tftStartWrite();
    SPI.transfer(lineBuffer, (charWidth * textsize * 2)); // 每个像素2字节
    tftEndWrite();
  }

  // 更新光标位置
  cursor_x += 6 * textsize;
}

// 浮点数值显示
void printFloat(float value, int16_t x, int16_t y, uint8_t intlength, uint8_t dotlength, uint8_t length) {
  char buffer[length + 1]; 
  dtostrf(value, intlength, dotlength, buffer); // 更高效的转换
  // 计算需要补零的数量（考虑负号和小数点）
  int zerosNeeded = length - strlen(buffer);
  if (zerosNeeded > 0) {
    // 移动现有字符串到缓冲区右侧
    memmove(buffer + zerosNeeded, buffer, strlen(buffer) + 1);
    // 在开头填充'0'
    memset(buffer, '0', zerosNeeded);
  }
  textsize = 5;
  printAt(x, y, buffer);
}

// 优化位置显示
void printAt(int16_t x, int16_t y, const char *str) {
  setCursor(x, y);
  while (*str) drawChar(*str++);
}

// ==================== 主程序 (优化刷新) ====================
void setup() {
  // 初始化背光控制
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH); // 开启背光
  // analogWrite(TFT_BL, 200);  //analogWrite太占flash了，不用了
  
  // 初始化屏幕
  tftInit();
  // 绘制静态界面
  tftFillArea(0, 0, 240, 240, 0x0000);  // 黑色背景
  tftFillArea(4, 4, 232, 55, 0xF81F);
  tftFillArea(4, 63, 232, 55, 0x001F);
  tftFillArea(4, 122, 232, 55, 0xFFE0);
  tftFillArea(4, 181, 232, 55, 0x07E0);

  // 设置微型字体
  textsize = 5; // 使用5倍大小         
  setTextColor(0x0000, 0xF81F);
  printAt(207, 16, "V");
  setTextColor(0x0000, 0x001F);
  printAt(207, 75, "A");
  setTextColor(0x0000, 0xFFE0);
  printAt(207, 134, "W");
  setTextColor(0x0000, 0x07E0);
  printAt(180, 193, "Wh");
}

void loop() {
  static float loadvoltage = 3.0;
  static float current_A = 0.5;
  static float capacity_mWh = 0.00000;
  static uint32_t start_time = millis();

  // 每500ms更新一次显示
  if ((millis() - start_time) >= 500) {
    start_time = millis();

    // 模拟值变化
    loadvoltage += 0.13;
    current_A += 0.051;
    
    if (loadvoltage > 5.0) loadvoltage = 3.0;
    if (current_A > 3.0) current_A = 0.5;
    
    // 计算功率
    float power_mW = loadvoltage * current_A * 1000.0;
    // 计算电量
    capacity_mWh = capacity_mWh + power_mW * 0.5 / 3600;    //mW * 500ms转化位mWh
    Display_Current(loadvoltage, current_A, power_mW, capacity_mWh);
  }
}

void Display_Current(float loadvoltage, float current_A, float power_mW, float capacity_mWh){
  //显示电压如12.853 V
  setTextColor(0x0000, 0xF81F);
  printFloat(loadvoltage, 8, 16, 2, 3, 6);
  
  //显示电流如2.0011A
  setTextColor(0x0000, 0x001F);
  printFloat(current_A, 8, 75, 1, 4, 6);
  
  
  //功率<1000.0mW显示为mW, 小数点前3位后1位, 例如900.3mW
  //功率≥1000.0mW并＜10000.0mW显示为W, 小数点前1位后3位, 例如1.005W
  //功率大于等于10000.0mW显示为W, 小数点前2位后2位, 例如48.05W
  setTextColor(0x0000, 0xFFE0);
  if (power_mW < 1000) {
    printFloat(power_mW, 8, 134, 3, 1, 5);
    textsize = 4;
    printAt(183, 141, "m");
  } else if (power_mW < 10000) {
    float power_W = power_mW / 1000;
    printFloat(power_W, 8, 134, 1, 3, 5);
    textsize = 4;
    printAt(183, 141, " ");//把m清掉
  } else {
    float power_W = power_mW / 1000;
    printFloat(power_W, 8, 134, 2, 2, 5);
    textsize = 4;
    printAt(183, 141, " ");//把m清掉
  }
  
  
  //电量取0.001~9.999mWh和00.01WH~48.00Wh
  setTextColor(0x0000, 0x07E0);
  if (capacity_mWh < 10) {
    printFloat(capacity_mWh, 8, 193, 1, 3, 5);
    textsize = 4;
    printAt(156, 200, "m");
  } else {
    float capacity_Wh = capacity_mWh / 1000;
    unsigned int mwh = int(capacity_mWh) % 10;
    char mwh_char[2];
    itoa(mwh, mwh_char, 10);
    printFloat(capacity_Wh, 8, 193, 2, 2, 5);
    textsize = 4;
    printAt(156, 200, mwh_char); //把m清掉用小号的字体替代
  }
}
